package link.jfire.jnet.server.CompletionHandler;

import java.nio.channels.AsynchronousCloseException;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.CompletionHandler;
import link.jfire.baseutil.disruptor.Disruptor;
import link.jfire.baseutil.simplelog.ConsoleLogFactory;
import link.jfire.baseutil.simplelog.Logger;
import link.jfire.jnet.server.server.AioServer;
import link.jfire.jnet.server.server.ChannelInitListener;
import link.jfire.jnet.server.server.ServerChannelInfo;
import link.jfire.jnet.server.server.ServerConfig;

public class AcceptHandler implements CompletionHandler<AsynchronousSocketChannel, Object>
{
	private AioServer				aioServer;
	private Logger					logger				= ConsoleLogFactory.getLogger();
	private ServerConfig			config;
	private ChannelReadHandler		channelReadHandler;
	private ChannelWriteHandler		channelWriteHandler	= new ChannelWriteHandler();
	private ChannelInitListener[]	initListeners;
	private Disruptor				disruptor;
	
	public AcceptHandler(AioServer aioServer, ServerConfig serverConfig)
	{
		config = serverConfig;
		this.initListeners = serverConfig.getInitListeners();
		this.aioServer = aioServer;
		channelReadHandler = new ChannelReadHandler(serverConfig.getFrameDecodec());
		ServerInternalResultAction[] actions = new ServerInternalResultAction[serverConfig.getHandlerThreadSize()];
		for (int i = 0; i < actions.length; i++)
		{
			actions[i] = new ServerInternalResultAction();
		}
		disruptor = new Disruptor(serverConfig.getRingArraySize(), serverConfig.getWaitStrategy(), actions, serverConfig.getRingArrayType(), serverConfig.getHandlerThreadSize());
	}
	
	public void stop()
	{
		disruptor.stop();
	}
	
	@Override
	public void completed(AsynchronousSocketChannel socketChannel, Object attachment)
	{
		try
		{
			ServerChannelInfo channelInfo = new ServerChannelInfo(socketChannel, channelReadHandler, channelWriteHandler, disruptor);
			channelInfo.setReadTimeout(config.getReadTiemout());
			channelInfo.setWaitTimeout(config.getWaitTimeout());
			if (initListeners != null)
			{
				for (ChannelInitListener each : initListeners)
				{
					each.channelInit(channelInfo);
				}
			}
			logger.debug("开启一个新通道{}", channelInfo.getAddress());
			channelInfo.startReadWait();
			aioServer.getServerSocketChannel().accept(null, this);
		}
		catch (Exception e)
		{
			logger.error("注册异常", e);
		}
	}
	
	@Override
	public void failed(Throwable exc, Object attachment)
	{
		if (exc instanceof AsynchronousCloseException)
		{
			logger.info("服务端监听链接被关闭");
		}
		else if (exc instanceof ClosedChannelException)
		{
			logger.info("服务端监听链接被关闭");
		}
		else
		{
			logger.error("链接异常关闭", exc);
		}
		Thread.currentThread().interrupt();
	}
	
}
